﻿using Application_Core.Arbeitsplan_Component.Access_Layer.Exceptions;
using Application_Core.Arbeitsplan_Component.Business_Logic_Layer;
using Application_Core.Arbeitsplan_Component.Data_Access_Layer;
using Application_Core.Arbeitsplan_Component.Data_Access_Layer.Implementations;
using System;
using System.Collections.Generic;
using Utility.Global.Utilities;
using Utility.Persistence_Service;

namespace Application_Core.Arbeitsplan_Component.Access_Layer
{
    public class ArbeitsplanComponentFacade : ArbeitsplanService, ArbeitsplanInternalService
    {
        private readonly UnitOfWork unitOfWork;
        private readonly ArbeitsplanComponentBusinessLogic arbeitsplanLogic;
        private readonly ArbeitsplanRepository arbeitsplanRepo;
        private readonly VorgangRepository vorgangRepo;

        public ArbeitsplanComponentFacade(UnitOfWork unitOfWork)
        {
            this.unitOfWork = unitOfWork;
            this.arbeitsplanLogic = new ArbeitsplanComponentBusinessLogicImpl(unitOfWork);
            this.arbeitsplanRepo = new ArbeitsplanRepositoryImpl(unitOfWork);
            this.vorgangRepo = new VorgangRepositoryImpl(unitOfWork);
        }

        public void CreateArbeitsplan(ArbeitsplanDTO arbeitsplanDTO, int bauteilId, List<VorgangDTO> vorgängeDTOs)
        {
            Check.Argument(arbeitsplanDTO != null, "DataTransferObjekt von Arbeitsplan wird benötigt.");
            Check.Argument(vorgängeDTOs.Count > 0, "Mindestens ein Vorgang muss im Arbeitsplan vorhanden sein.");

            // Positionen prüfen und zu Entities umwandeln
            Arbeitsplan arbeitsplan = arbeitsplanDTO.ToEntity();
            arbeitsplan.BauteilId = bauteilId; // TODO: Abhängigkeit zu BauteilKomponente schaffen oder ID->Nummer
            List<Vorgang> vorgänge = new List<Vorgang>();
            foreach (VorgangDTO vorgang in vorgängeDTOs)
            {
                Check.Argument(vorgang != null, "DataTransferObjekt von Vorgang wird benötigt (darf nicht null sein).");
                vorgänge.Add(vorgang.ToEntity());
            }

            // Save
            Arbeitsplan savedArbeitsplan = this.arbeitsplanRepo.Create(arbeitsplan);
            foreach (Vorgang vorgang in vorgänge)
            {
                vorgang.Arbeitsplan = savedArbeitsplan;
                this.vorgangRepo.Create(vorgang);
            }
        }

        #region Internal

        public bool HasArbeitsplan(int bauteilId)
        {
            Arbeitsplan arbeitsplan = this.arbeitsplanRepo.FindByBauteilId(bauteilId);
            return (arbeitsplan != null);
        }

        public TimeSpan BerechneFertigungszeit(int bauteilId, int menge)
        {
            Arbeitsplan arbeitsplan = this.arbeitsplanRepo.FindByBauteilId(bauteilId);
            if (arbeitsplan == null)
            {
                throw new ArbeitsplanNotFoundException("Es wurde kein Arbeitsplan zu einem Bauteil gefunden.");
            }

            // Berechnung durch die Business Logic
            return this.arbeitsplanLogic.BerechneFertigungszeit(arbeitsplan, menge);
        }

        #endregion
    }
}
